﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace BReusable.StaticReflection
{
    /// <summary>
    /// BReusable
    /// http://jonfuller.codingtomusic.com/2008/12/11/static-reflection-method-guards/
    /// </summary>
    public static class Guard
    {

        public static void IsTrue(Expression<Func<bool>> expr)
    {
        var func = expr.Compile();
        System.Diagnostics.Debug.Assert(func());
        if (func() == false)
            throw new InvalidOperationException("Assertion:" + expr.ToString() + " failed");
    }

        /// <summary>
        /// Throw an argument null exception WITH the name of the argument
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr"></param>
        public static void IsNotNullStatic<T>(Expression<Func<T>> expr)
            where T : class
        {
            if (expr.Compile()() != null)
                return;
            var param = (MemberExpression)expr.Body;
            throw new ArgumentNullException(param.Member.Name);

        }
        /// <summary>
        /// IL based retrieval
        /// http://abdullin.com/journal/2008/12/19/how-to-get-parameter-name-and-argument-value-from-c-lambda-v.html
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="argument"></param>
        public static void IsNotNullIL<T>(Func<T> argument) where T:class
        {
            if (null == argument())
                throw ArgumentNull(argument);
        }

        private static ArgumentNullException ArgumentNull<T>(Func<T> argument)
        {
            // get IL code behind the delegate
            var il = argument.Method.GetMethodBody().GetILAsByteArray();
            // bytes 2-6 represent the field handle
            var fieldHandle = BitConverter.ToInt32(il, 2);
            // resolve the handle
            var field = argument.Target.GetType()
              .Module.ResolveField(fieldHandle);
            var name = field.Name;

            var message = string.Format(
              "Parameter of type '{0}' can't be null", typeof(T));
            return new ArgumentNullException(name, message);
        }
    }
}
